package com.maschinenstuermer.profiler.config.impl;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Logger;
import java.util.regex.Pattern;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Config {
	private static final Logger logger = Logger.getLogger(Config.class.getName());
	
	@XmlAttribute
	private String destDir = "";

	@XmlElement
	private List<String> include = new ArrayList<String>();

	@XmlElement
	private List<String> exclude = new ArrayList<String>();

	@XmlAttribute
	private boolean enableJdbcTracing;

	@XmlAttribute
	private boolean enableTransactionTracing = true;

	private transient Pattern includedClasses;
	
	private transient Pattern excludedClasses;
	
	public Config() {
	}

	public String getDestDir() {
		return destDir;
	}

	public boolean isEnableJdbcTracing() {
		return enableJdbcTracing;
	}

	public boolean isEnableTransactionTracing() {
		return enableTransactionTracing;
	}

	public void addInclude(String include) {
		if (!this.include.contains(include)) {
			this.include.add(include);
			includedClasses = null;
		}
	}
	
	public void addExclude(String exclude) {
		if (!this.exclude.contains(exclude)) {
			this.exclude.add(exclude);
			excludedClasses = null;
		}
	}
	
	public Pattern getIncludedClasses() {
		if (includedClasses == null) {
			includedClasses = createPattern(include);
			logger.info("created included classes pattern:" + includedClasses.toString());
		}
		return includedClasses;
	}

	public Pattern getExcludedClasses() {
		if (excludedClasses == null) {
			excludedClasses = createPattern(exclude);
			logger.info("created excludeded classes pattern:" + excludedClasses.toString());
		}
		return excludedClasses;
	}

	/**
	 * Used for testing.
	 * @return
	 */
	public List<String> getIncludes() {
		return include;
	}
	
	/**
	 * Used for testing.
	 * @return
	 */
	public List<String> getExcludes() {
		return exclude;
	}
	
	private static Pattern createPattern(List<String> fileRegexps) {
		StringBuffer buffer = new StringBuffer();
		for (Iterator<String> iterator = fileRegexps.iterator(); iterator.hasNext();) {
			String fileRegexp = iterator.next();
			String escapeDot = fileRegexp.replaceAll("\\.", "\\\\.");
			String escapeDoubleAsterix = escapeDot.replaceAll("\\*\\*", "&");
			String escapeAsterix = escapeDoubleAsterix.replaceAll("\\*", "[^.]*");
			String regexp = escapeAsterix.replaceAll("&", ".*");
			buffer.append("(").append(regexp).append(")");
			if (iterator.hasNext()) {
				buffer.append("|");
			}
		}
		String regex = buffer.toString();
		Pattern pattern = Pattern.compile(regex);
		return pattern;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((destDir == null) ? 0 : destDir.hashCode());
		result = prime * result + (enableJdbcTracing ? 1231 : 1237);
		result = prime * result + (enableTransactionTracing ? 1231 : 1237);
		result = prime * result + ((exclude == null) ? 0 : exclude.hashCode());
		result = prime * result + ((include == null) ? 0 : include.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Config other = (Config) obj;
		if (destDir == null) {
			if (other.destDir != null)
				return false;
		} else if (!destDir.equals(other.destDir))
			return false;
		if (enableJdbcTracing != other.enableJdbcTracing)
			return false;
		if (enableTransactionTracing != other.enableTransactionTracing)
			return false;
		if (exclude == null) {
			if (other.exclude != null)
				return false;
		} else if (!exclude.equals(other.exclude))
			return false;
		if (include == null) {
			if (other.include != null)
				return false;
		} else if (!include.equals(other.include))
			return false;
		return true;
	}
}
